﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.Caching;
using System.Web.Hosting;
using ImageResizer;
using ImageResizer.Resizing;

namespace Eksponent.CropUp.Plugins
{
    public class ImageResizerDialect : Dialect
    {
        public override string GetUrl(string virtualPath, ImageSizeArguments arguments)
        {
            if (string.IsNullOrEmpty(virtualPath)) return null;

            if (!virtualPath.StartsWith("~")) virtualPath = "~" + virtualPath;

            var args = new Dictionary<string, string>();
            if (arguments != null && (arguments.Width.HasValue || arguments.Height.HasValue || !string.IsNullOrEmpty(arguments.CropAlias)))
            {
                if (arguments.CropMode == CropUpMode.Max || arguments.CropMode == CropUpMode.Pad)
                {
                    args["mode"] = arguments.CropMode == CropUpMode.Max ? "max" : "pad";
                    if (arguments.Width.HasValue) args["width"] = "" + arguments.Width;
                    if (arguments.Height.HasValue) args["height"] = "" + arguments.Height;
                }
                else if (arguments.CropMode == CropUpMode.Min)
                {
                    if (arguments.Width.HasValue) args["width"] = "" + arguments.Width;
                    if (arguments.Height.HasValue) args["height"] = "" + arguments.Height;

                    args["width"] = "" + arguments.Width;
                    args["height"] = "" + arguments.Height;

                    if (arguments.Width.HasValue && arguments.Height.HasValue)
                    {
                        args["mode"] = "crop-up";
                        args["cropUpClientMode"] = "true";
                    }
                }
                else
                {
                    args["mode"] = "crop-up";

                    if (arguments.Width.HasValue) args["width"] = "" + arguments.Width;
                    if (arguments.Height.HasValue) args["height"] = "" + arguments.Height;
                    if (!string.IsNullOrEmpty(arguments.CropAlias))
                    {
                        args["cropUpAlias"] = arguments.CropAlias;
                    }

                    if (arguments.Box.HasValue)
                    {
                        var box = arguments.Box.Value;
                        args["cropUpBox"] = box.Left.ToString(ImageSizeArguments.UrlCulture)
                            + "," + box.Top.ToString(ImageSizeArguments.UrlCulture)
                            + "," + box.Right.ToString(ImageSizeArguments.UrlCulture)
                            + "," + box.Bottom.ToString(ImageSizeArguments.UrlCulture);
                    }

                    if (arguments.Gravity.HasValue)
                    {
                        var gravity = arguments.Gravity.Value;
                        args["cropUpGravity"] = gravity.X.ToString(ImageSizeArguments.UrlCulture) + "," + gravity.Y.ToString(ImageSizeArguments.UrlCulture);
                    }

                    if (arguments.Zoom)
                    {
                        args["cropUpZoom"] = "true";
                    }
                }
            }

            var sb = new StringBuilder(HttpUtility.UrlPathEncode(VirtualPathUtility.ToAbsolute(virtualPath)));
            if (args.Count > 0)
            {
                sb.Append("?");
                int i = 0;
                foreach (var arg in args)
                {
                    if (i++ > 0)
                    {
                        sb.Append("&");
                    }
                    sb.Append(arg.Key + "=" + HttpUtility.UrlEncode(arg.Value));
                }
            }

            return sb.ToString();
        }

        public override Size GetImageSize(string virtualPath)
        {
            using (var b = GetBitmap(virtualPath))
            {
                return b.Bitmap.Size;
            }
        }

        public override void ClearCache(string virtualPath)
        {
            HttpRuntime.Cache.Remove(GetSizeCacheKey(PathToAbsolute(virtualPath)));
        }

        string GetSizeCacheKey(string path)
        {
            return "CropUp.Size_" + path;
        }

        public string PathToAbsolute(string imageRelPath)
        {
            if (imageRelPath.StartsWith("/"))
                if (!imageRelPath.StartsWith("~")) imageRelPath = "~" + imageRelPath;
            if (imageRelPath.StartsWith("~")) imageRelPath = HostingEnvironment.MapPath(imageRelPath);
            return imageRelPath;
        }

        public override string GetResponsiveUrl(string virtualPath, bool progressive, bool zoom)
        {
            var url = GetUrl(virtualPath, progressive
                ? new ImageSizeArguments { CropMode = CropUpMode.Responsive, Width = 111, Height = 222 }
                : new ImageSizeArguments { CropMode = CropUpMode.BestFit, Width = 111, Height = 222, Zoom = zoom });

            return url.Replace("111", "{w}").Replace("222", "{h}");
        }


        public override IDisposableBitmap GetBitmap(string virtualPath)
        {
            return new DisposableBitmap(ImageBuilder.Current.LoadImage(virtualPath, new ResizeSettings()));
        }

        public class DisposableBitmap : IDisposableBitmap
        {
            public Bitmap Bitmap { get; set; }
            public DisposableBitmap(Bitmap bitmap)
            {
                Bitmap = bitmap;
            }

            public void Dispose()
            {
                Bitmap.Dispose();
                var tag = Bitmap.Tag as BitmapTag;
                if (tag != null && tag.Source != null)
                {
                    tag.Source.Dispose();
                }
            }
        }
    }
}
